
#include <iostream>
#include <fstream>
#include "Wav.h"
#include <cstdio>

#include "MediaInfo.h"
#include "..\SoundTouch\SoundTouch.h"
#include <QDebug>
using namespace std;


int to_pcm()
{
    char filename[50] = "d:\\test-file\\test.wmv";

    uint8_t *buffer= new uint8_t[192000];

    CMediaInfo media(MEDIA_TYPE::AUDIO);
    media.open(filename);

    AVPacket *packet = av_packet_alloc();
    AVFrame *frame = av_frame_alloc();

    auto duration = media.pFormatContext->duration + (media.pFormatContext->duration <= INT64_MAX - 5000 ? 5000 : 0);

    ofstream ofs("wildlife_touch.wav", ofstream::binary); // 变调后的wav
    ofstream origin_ofs("origin.wav", ofstream::binary); // 提取的原始的wav
    //    音频的采样格式分为平面（planar）和打包（packed）两种类型，在枚举值中上半部分是packed类型，后面（有P后缀的）是planar类型。
    //    对于planar格式的，每一个通道的值都有一个单独的plane，所有的plane必须有相同的大小；
    //    对于packed类型，所有的数据在同一个数据平面中，不同通道的数据交叉保存。
    AVSampleFormat dst_format = /*AV_SAMPLE_FMT_S16*/AV_SAMPLE_FMT_S16;//p不行
    uint8_t dst_channels =2;//1不行
    auto dst_layout = av_get_default_channel_layout(dst_channels);//根据通道的个数返回默认的layout
    auto audio_ctx = media.pAudio_codec_context;
    //channel_layout是一个64位整数，每个值为1的位对应一个通道。也就说，channel_layout的位模式中值为1的个数等于其通道数量。
    if (audio_ctx->channel_layout <= 0)
        audio_ctx->channel_layout = av_get_default_channel_layout(audio_ctx->channels);
    SwrContext *swr_ctx = swr_alloc();
//audio_ctx->sample_rate与原来音频采样率不同，则会慢放后快放的情况
    swr_alloc_set_opts(swr_ctx, dst_layout, dst_format, audio_ctx->sample_rate,
                       audio_ctx->channel_layout, audio_ctx->sample_fmt, audio_ctx->sample_rate, 0, nullptr);
    if (!swr_ctx || swr_init(swr_ctx))
        return -1;

    ////////////////////////////////////////////////////////////////////
    // 设置SoundTouch，配置变调变速参数 //pitch（音调）  tempo（节拍）  rate（速度）
    soundtouch::SoundTouch s_touch;
    s_touch.setSampleRate(audio_ctx->sample_rate); // 设置采样率
    s_touch.setChannels(audio_ctx->channels); // 设置通道数

    //s_touch.setRate(0.5);
    //s_touch.setRateChange(-50.0);
    //s_touch.setTempo(1.1);
    s_touch.setPitch(1);
    s_touch.setSetting(SETTING_USE_QUICKSEEK, 1);
    s_touch.setSetting(SETTING_USE_AA_FILTER, 1);

    soundtouch::SAMPLETYPE touch_buffer[96000];

    int pcm_data_size = 0;
    int origin_data_size = 0;
    while (av_read_frame(media.pFormatContext, packet) >= 0)
    {
        if (packet->stream_index == media.audio_stream_index)
        {
            auto ret = avcodec_send_packet(media.pAudio_codec_context, packet);

            if (ret < 0 && ret != AVERROR(EAGAIN) && ret != AVERROR_EOF)
                return -1;

            ret = avcodec_receive_frame(media.pAudio_codec_context, frame);
            if (ret < 0 && ret != AVERROR_EOF)
                return -1;

            //返回值为转换的sample个数,buffer输出缓冲区，out_count每个通道的输出大小
            auto nb = swr_convert(swr_ctx, &buffer, 192000, (const uint8_t **)frame->data, frame->nb_samples);

            //////////////////////////////////////////////////////////////
            // 传入sample，并接收处理后的sample

            // 将解码后的buffer(uint8*)转换为soundtouch::SAMPLETYPE，也就是singed int 16
            //av_get_bytes_per_sample返回每个采样值所占用的字节数
            auto len = nb * dst_channels * av_get_bytes_per_sample(dst_format);//采样个数*声道数*每个采样所占字节数=总字节数

//            origin_ofs.write((char*)buffer, len);
//            origin_data_size += len;

            for (auto i = 0; i < len; i++)
            {
                //16bit->8bit
                touch_buffer[i] = (buffer[i * 2] | (buffer[i * 2 + 1] << 8));
            }

            // 16位有符号整数的最大值 0x7FFF => 32767   20 * log(sample / 32767) = #dBFS

            // 10ms的sample  10 * 44100 / 1000 = 441 个sample

            // 传入Sample
            //            s_touch.setSampleRate(audio_ctx->sample_rate); // 设置采样率
            //            s_touch.setChannels(audio_ctx->channels); // 设置通道数

            //            //s_touch.setRate(0.5);
            //            //s_touch.setRateChange(-50.0);
            //            //s_touch.setTempo(1.1);
            //            s_touch.setPitch(0.4);
            //            s_touch.setSetting(SETTING_USE_QUICKSEEK, 1);
            //            s_touch.setSetting(SETTING_USE_AA_FILTER, 1);//放这里也可以，
            //            soundtouch::SAMPLETYPE touch_buffer[96000]; //放这里也可以，

            //第二个参数就是要处理多少个sample也可以理解为多少帧。
            s_touch.putSamples(touch_buffer, nb);//第一个参数SAMPLETYPE *samples，指向一个以PCM编码的wave数据缓冲区，第二个参数uint nSamples，就是这个数据缓冲区包含的Sample个数
            qDebug()<<"1"<<nb;
            do
            {
                // 接收处理后的sample
                nb = s_touch.receiveSamples(touch_buffer, 96000);
                qDebug()<<"2"<<nb;
                auto length = nb * dst_channels * av_get_bytes_per_sample(dst_format);
                ofs.write((char*)touch_buffer, length);

                pcm_data_size += length;

                {
                    for (int i = 0; i <length; i++) {//另种方式去写
                        //high = (touch_buffer[i] >> 8) & 0xff; //高8位
                        //low = touch_buffer[i] & 0xff; //低8位

                        buffer[i * 2+1] = (touch_buffer[i] >> 8) & 0xff; //高8位
                        buffer[i * 2] = touch_buffer[i] & 0xff; //低8位
                    }

                    origin_ofs.write((char*)buffer, length);
                    origin_data_size += length;
                }


            } while (nb != 0);
        }
        av_packet_unref(packet);
    }

    ///////////////////////////////////////////////
    // 接收管道内余下的处理后数据
    s_touch.flush();
    int nSamples;
    do
    {
        nSamples = s_touch.receiveSamples(touch_buffer, 96000);

        auto length = nSamples * dst_channels * av_get_bytes_per_sample(dst_format);
        ofs.write((char*)touch_buffer, length);

        //        for (auto i = 0; i < length; i++)
        //        {
        //            buffer[i * 2 ] =  touch_buffer[i] & 0xff; //低8位
        //            buffer[i * 2+ 1] =   ( touch_buffer[i] >> 8) & 0xff; //高8位
        //        }
        //        origin_ofs.write((char*)buffer, length);//

        pcm_data_size += length;
    } while (nSamples != 0);

    // 写Wav文件头
    Wave_header header(dst_channels, audio_ctx->sample_rate, av_get_bytes_per_sample(dst_format) * 8);
    header.data->cb_size = ((pcm_data_size + 1) / 2) * 2;
    header.riff->cb_size = 4 + 4 + header.fmt->cb_size + 4 + 4 + header.data->cb_size + 4;

    ofs.seekp(0, ios::beg);
    CWaveFile::write_header(ofs, header);

    ofs.close();

    header.data->cb_size = ((origin_data_size + 1) / 2) * 2;
    header.riff->cb_size = 4 + 4 + header.fmt->cb_size + 4 + 4 + header.data->cb_size + 4;
    origin_ofs.seekp(0, ios::beg);
    CWaveFile::write_header(origin_ofs, header);

    origin_ofs.close();

    delete[] buffer;
    swr_free(&swr_ctx);
    av_packet_free(&packet);
    av_frame_free(&frame);

    media.close();

    return 0;
}




int main()
{
    to_pcm();

    cout << "end." << endl;
    getchar();
    return 0;
}


